Mashed Potato Sculpture Simulator by François Vander Linden

How many times were you told not to play with food ? Well ... now you can ! thanks to my third contribution for Roby Sherman's "Fancy Screen Stuff 2-liner contest".
So far, all "fancy screen stuff 2-liners" were drawing stuff on the screen FOR YOU ! Now, you'll create fancy screen stuff yourself.
The program is called "Mashed Potato Sculpture Simulator".
You finally have the opportunity to wake up the child sculptor in you !
Use your (virtual) knife and fork and sculpt the mashed potato: carve eyes, mouths, ears. Create friendly faces, animals, buildings or scary aliens, it's up to you, the Artist.
The screen present a pile of mashed potato.
In order to sculpt it, you use your fork and knife. You only see the cross section of the blade and of the fork but you're able to rotate your tools.
The fork and knife move symmetrically to each other from the center of the screen (which is also the center of the mashed potato pile). They also rotate symmetrically.
You have the ability to either carve or fill holes with more mashed potato. This last feature allows you for instance to grow "arms" to your mashed potato pile.
Use the J-key to move one of the cutlery to the left (and the other to the right) or the L-key to to the opposite. Use the K-key to stop the horizontal movement.
The joystick controls the vertical position of the knife & fork if you move it up and down. The left and right direction of the joystick allow you to rotate your tools.
Center the joystick to stop moving your cutlery vertically and stop the rotation.
Press button #0 to carve the mashed potato with your cutlery and press button #1 to add more mashed potato with your cutlery.
To quit the program simply press CTRL-C ... you may then save your work with a classic BSAVE myfile,A$2000,L$2000.
The controls might seem weird at first but the imprecision of the Apple ][ joystick gives little choice. With a little practice, you'll be able to sculpt nice stuff.
The best strategy is to start moving your cutlery using J or L and then press the carve/fill button, rotate your tools and change the vertical position WHILE moving and carving and you'll obtain nice mashed potato sculptures.
The movement of the cutlery is voluntarily slow so you have the time (?) to adjust the rotation and position of your fork and knife.
Sculpture (even though it's only mashed potato) is an art that requires patience. Patience, concentration and skilled hands.
Post captures of your best work for everyone to enjoy !
And have fun !
PS: it's while I was working on this program and testing different stuff that the idea for the game SLALOM came.
Here's the 2-liner code. Then an line-by-line explanation. A DSK will follow.
=================
0POKE184,43-Z:ROT=R:XDRAW1ATS,Y:ROT=64-R:XDRAW1AT278-S,Y:RETURN:HOME:INVERSE:?"A@D@D@":POKE232,0:POKE233,4:DEFFNS(N)=INT(N/64-1.99+(N<128)):SCALE=10:HGR:HCOLOR=3:FORI=0TO159:HPLOT119-Y,ITO159+Y,I:Y=Y+RND(1)*3-1:NEXT:R=8:FORQ=0TO1:X=PDL(0)
1Z=29:R=R+FNS(X):R=R*(R>0ANDR<64):K=PDL(1):Y=Y+FNS(K):Y=Y*(Y>0ANDY<I):K=PEEK(-4^7):S=S+(K-203)*(K>201):S=S*(S>0ANDS<279):GOSUB:C=PEEK(49250)>127:B=PEEK(49249)>127ORC:HCOLOR=C*3:GOSUB:K=Y*B+175*NOTB:DRAW1AT278-S,K:ROT=R:DRAW1ATS,K:Q=0:NEXT
=========================================
Code explained (note that typing this code won't work)
0 POKE 184,43-Z: REM This code, when first run, will point the Applesoft interpreter pointer to the statement in line 6 (HOME:INVERSE). On the next occurences, it will simply point to the next statement. This is because the next lines/statements are used as a GOSUB subroutine.
1 ROT=R : REM Start of the GOSUB subroutine. We set shape ROTation to value of R
2 XDRAW 1 AT S,Y : REM we draw shape 1 at S,Y. Shape 1 is a line representing the cross-section of a knife/fork.
3 ROT=64 - R : REM ROTation is changed to its "symmetrical" value so we can draw the 2nd cutlery symmetrically
4 XDRAW 1 AT 278-S,Y : REM we draw the 2nd cutlery symmetrically to the first one.
5 RETURN : REM end of the subroutine
6 HOME: INVERSE : REM Clear the screen, go to INVERSE mode. We are going to PRINT a shape table in $400 using INVERSE characters.
7 ? "A@D@D@" : REM The resulting bytes in $400 are valid instructions for a shape table. This shape is only one instruction: plot and move up.
8 POKE 232,0 : REM these two POKEs indicate where the shape table is located ($0400). This is the low-byte.
9 POKE 233,4 : REM This is the high byte of $0400
10 DEF FN S(N) = INT( N/64 - 1.99 + (N<128)) : REM now we define a "function". This function will be used twice in the code. Using DEF FN saves a few chars. This function will translate a PDL value (variable N from 0-255) to a range of -1, 0 or +1 as integers. It will be used to scale the X or Y axis of the joystick to -1, 0 or 1 allowing us to increment/decrease the ROTation of the cutlery or its Y-position. The INT instruction behaves strangely with negative numbers because INT(-0.1) will give -1 instead of 0 (which is the real INTeger part of that number). To compensate for that, we add 1 to the final result. The 1.99 is used instead of 2 because otherwise for N=0 we would have -2 and not -1 as we wanted.
11 SCALE=10 : REM Our shape table of 1 pixel will be displayed as a line of 10 pixels !
12 HGR : REM the Hires screen is cleared
13 HCOLOR= 3 : REM the hires color is set to white #1
14 FOR I = 0 TO 159 : REM now we go from the top of the screen to the bottom
15 HPLOT 119-Y, I TO 159+Y, I : REM and we draw a pile of mashed potato ... the top of the pile being 40 pixels wide.
16 Y = Y + RND(1) * 3 - 1 : REM the next "line" of the pile will be from -1 to 2 pixels wider ..
17 NEXT
18 R=8 : REM this is the base rotation value .... this could have been omitted from the 2-liner if more chars were needed ...
19 FOR Q = 0 TO 1 : REM this begins the main loop ... it will be infinite ... see line 39
20 X=PDL(0) : REM we read PDL 0
21 Z=29 : REM This is the beginning of the 2nd line of the 2-liner. This variable is initialized here and is used in line 0 to "not skip" the subroutine. Its logical place would have been outside the main loop but we didn't have enough characters left on line zero of the 2-liner.
22 R=R + FN S(X) : REM R will hold the actual rotation of the tools. We call the FN we DEFined a few lines earlier. So a value of -1, 0 or 1 is added to R.
23 R=R * (R>0 AND R<64) : REM This line makes sure that R is between 0 and 64. Values above 64 (but below 256) are valid for ROT but negative values are not.
24 K=PDL(1) : REM we read PDL 1 value
25 Y=Y + FN S(K) : REM and we apply the same FN to its value. The vertical drift will be -1, 0 or +1 pixel.
26 Y=Y * (Y>0 AND Y<I) : REM and again we make sure that Y is between valid limits. Notice how we use "I" that was the loop variable to draw the pile of mashed potato. At this stage its value is 160. Just what we need. We saved 2 characters that way.
27 K = PEEK (-4^7) : REM this reads a character from the keyboard buffer. -4^7 equals -16384. It's only 4 characters instead of 6 (or 5 for the 49152 equivalent).
28 S=S + (K-203)*(K>201) : REM here we cheat a little. The value for the J/K/L keys are 202/203/204. By substracting 203, we have now -1/0/+1 but if you press M-key you'll have +2 and we don't check that. So, S, which is the X-position of the leftmost cutlery (278-S is the position of the rightmost cutlery) is modified by a factor of -1/0/+1/+2/...
29 S=S * (S>0 AND S<279) : REM however we have to make sure that final position of S is still between the screen limits. If it's not we go back to position ZERO. Due to characters limitation I had to remove a part of this equation that would not "loop" the position back to ZERO if position 280 was reached.
30 GOSUB : REM we now call the subroutine. We don't need to specify a line because it's line 0. The subroutine will Xdraw the cross-section of the fork and knife. The next call will undraw it.
31 C = PEEK(49250) > 127 : REM we check button #1 and check if it's pressed.
32 B = PEEK(49249) > 127 OR C : REM same for button #0 except we take into account button #1 too ... in early development stages B was ONLY button #0 state but it appeared that using/testing B later in the code was always done with C, so now, in order to save a few characters, B holds the fact that button #0 OR button #1 was pressde.
33 HCOLOR = C*3 : REM if we pressed the button #1, color is set to white. In all other cases, it's black !
34 GOSUB : REM we now erase the cutlery using our subroutine ...
35 K= Y * B + 175 * NOT B : REM K will hold either Y (our cutlery vertical position) if button #0 or #1 has been pressed or 175 if none were pressed. As explained of a line earlier, because B is 1 if at least one of the buttons has been pressed, it's much simpler that if B as holding only the state of button #0
36 DRAW 1 AT 278-S, K : REM we carve/fill using DRAW and the current HCOLOR (not XDRAW !). ROT equals 64-R because we've called our GOSUB routine, so this will DRAW the cutlery on the right.
37 ROT=R : REM now change ROT back so we can ...
38 DRAW 1 AT S, K : REM draw the leftmost cutlery
39 Q=0 : REM We want an infinite loop, so Q=0 every time ...
40 NEXT : REM the (infinite) end !